﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Remoting.Channels;
using System.Windows.Input;
using Commands.Settings;
using Commands.GetCommands;
using AE.Net.Mail;

namespace Commands
{
    internal class GetCommandsEmailAENet: IGetCommands
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="serverName"></param>
        public GetCommandsEmailAENet(MailSettings credentials, CommandStringParser parser)
        {
            _credentials = credentials;
            _commandsParser = parser;
        }

        /// <summary>
        /// List of addreses which from which commands will be executed.
        /// </summary>
        public List<string> AllowedAddress
        {
            get
            {
                if (_allowedAddress == null)
                {
                    _allowedAddress = new List<string>();
                }
                return _allowedAddress;
            }
            set { _allowedAddress = value; }
        }

        public IEnumerable<Command> GetCommands()
        {
            using (var imapClient = new ImapClient(_credentials.IMAPServer,
                _credentials.UserName, _credentials.Password, AE.Net.Mail.AuthMethods.Login, _credentials.IMAPPort,
                _credentials.SSL, false))
            {
                var message = _GetMessage(imapClient);

                return _GetCommandsFromMessage(message);
            }
        }

        /// <summary>
        /// Get message from mail box, save attachments to folder with this program.
        /// Get last received message from allowed address.
        /// </summary>
        /// <returns>String with message.</returns>
        private MessageSummary _GetMessage(IMailClient client)
        {
            int i = client.GetMessageCount() - 1;
            while (i >= 0)
            {
                // Get next message.
                var message = client.GetMessage(i);

#if DEBUG
#else
                client.DeleteMessage(message);
#endif

                i--;

                if (message.Flags.HasFlag(Flags.Deleted))
                    continue;

                // If message's address is in white list and message isn't read
                // parse this message.
                if (_IsAddressAllowed(message.From.Address))
                {
                    try
                    {
                        var result = new MessageSummary
                        {
                            Text = message.Body,
                            SenderAddres = message.From.Address,
                            AttachedFilesPath = _SaveAttachments(message),
                            Subject = message.Subject
                        };

                        return result;
                    }
                    catch (ArgumentNullException ex)
                    {
                    }
                }
            }

            return null;
        }

        /// <summary>
        /// Check is address allowed.
        /// </summary>
        /// <param name="address">Address to check.</param>
        private bool _IsAddressAllowed(string address)
        {
            if (AllowedAddress == null || AllowedAddress.Count == 0)
                return true;
            else
                return AllowedAddress.Contains(address);
        }

        /// <summary>
        /// Save attachments.
        /// </summary>
        /// <param name="message">Message.</param>
        private string _SaveAttachments(MailMessage message)
        {
            var attachesFolderPath = FilesHelper.GetAttachmentsFolder();

            foreach (var file in message.Attachments)
                file.Save(Path.Combine(attachesFolderPath, file.Filename));

            Zipper.UnzipFolder(attachesFolderPath);

            return attachesFolderPath;
        }

        /// <summary>
        /// Parse message and get command list.
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        private IEnumerable<Command> _GetCommandsFromMessage(MessageSummary message)
        {
            if (message == null)
                return new List<Command>();

            // Try to get command from subject.
            // If we got no commands from subject - get commands from message body.
            var result = CommandStringParser.ParseCommandsFromSubject(message.Subject, message.Text) ??
                         _commandsParser.ParseCommandsString(message.Text);

            foreach (var command in result)
            {
                // If files was saved in other folder, add parameter with folder name to each command.  
                if (!string.IsNullOrEmpty(message.AttachedFilesPath))
                    command.FolderWithSavedAttachesPath = message.AttachedFilesPath;

                command.SenderAddress = message.SenderAddres;
            }

            return result;
        }

        #region Fields

        private List<string> _allowedAddress;
        private MailSettings _credentials;
        private CommandStringParser _commandsParser;
        
        #endregion
    }
}
